(function () {
  const canvas = document.createElement('canvas')
  canvas.width = 1000
  canvas.height = 1000
  const gl = canvas.getContext('webgl2')
  const width = gl.drawingBufferWidth
  const height = gl.drawingBufferHeight

  function print(msg) {
    const line = document.createElement('div')
    line.innerText = msg
    document.body.appendChild(line)
  }

  function logCompileShader(shader, name) { // DEBUG
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      print('COMPILATION ERROR (' + name + '):\n' + gl.getShaderInfoLog(shader))
    }
  }

  function logLinkShader(program) { // DEBUG
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
      print('LINKING ERROR:\n' + gl.getProgramInfoLog(program))
    }
  }

  function createShaderProgram(vertSource, fragSource) {
    const vShader = gl.createShader(gl.VERTEX_SHADER)
    const fShader = gl.createShader(gl.FRAGMENT_SHADER)

    gl.shaderSource(vShader, vertSource)
    gl.shaderSource(fShader, fragSource)
    gl.compileShader(vShader)
    logCompileShader(vShader, 'VERTEX SHADER') // DEBUG
    gl.compileShader(fShader)
    logCompileShader(fShader, 'FRAGMENT SHADER') // DEBUG

    const program = gl.createProgram()
    gl.attachShader(program, vShader)
    gl.attachShader(program, fShader)
    gl.linkProgram(program)
    logLinkShader(program) // DEBUG

    gl.deleteShader(vShader)
    gl.deleteShader(fShader)

    return program
  }

  gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    -1, -1,
     1, -1,
    -1,  1,
    -1,  1,
     1, -1,
     1,  1
  ]), gl.STATIC_DRAW)
  gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0)
  gl.enableVertexAttribArray(0)

  const program = createShaderProgram(vertSrc, getFragSrc(width, height))
  gl.useProgram(program)

  gl.uniform1uiv(gl.getUniformLocation(program, 'T'), [
    0xD76AA478,0xE8C7B756,0x242070DB,0xC1BDCEEE,0xF57C0FAF,0x4787C62A,0xA8304613,0xFD469501,
    0x698098D8,0x8B44F7AF,0xFFFF5BB1,0x895CD7BE,0x6B901122,0xFD987193,0xA679438E,0x49B40821,
    0xF61E2562,0xC040B340,0x265E5A51,0xE9B6C7AA,0xD62F105D,0x02441453,0xD8A1E681,0xE7D3FBC8,
    0x21E1CDE6,0xC33707D6,0xF4D50D87,0x455A14ED,0xA9E3E905,0xFCEFA3F8,0x676F02D9,0x8D2A4C8A,
    0xFFFA3942,0x8771F681,0x6D9D6122,0xFDE5380C,0xA4BEEA44,0x4BDECFA9,0xF6BB4B60,0xBEBFBC70,
    0x289B7EC6,0xEAA127FA,0xD4EF3085,0x04881D05,0xD9D4D039,0xE6DB99E5,0x1FA27CF8,0xC4AC5665,
    0xF4292244,0x432AFF97,0xAB9423A7,0xFC93A039,0x655B59C3,0x8F0CCC92,0xFFEFF47D,0x85845DD1,
    0x6FA87E4F,0xFE2CE6E0,0xA3014314,0x4E0811A1,0xF7537E82,0xBD3AF235,0x2AD7D2BB,0xEB86D391
  ])
  gl.uniform1iv(gl.getUniformLocation(program, 's'), [
    7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
    5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
    4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
    6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
  ])
  gl.uniform1iv(gl.getUniformLocation(program, 'm'), [
    0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
    1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
    5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
    0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
  ])

  const input = document.createElement('input')
  input.style.width = '250px'
  input.value = 'e10adc3949ba59abbe56e057f20f883e'
  document.body.appendChild(input)

  const button = document.createElement('button')
  button.innerText = 'CALC'
  button.onclick = () => {
    if (input.value.length != 32 || !/^[0-9A-Fa-f]+$/.test(input.value)) {
      print('invalid md5')
      return
    }

    const target = []
    for (let i = 0; i < 4; i++) {
      let num = 0
      for (let j = 0; j < 4; j++) {
        num |= Number('0x' + input.value.substring(i * 8 + j * 2, i * 8 + j * 2 + 2)) << (j * 8)
      }
      target.push(num)
    }

    gl.uniform4ui(gl.getUniformLocation(program, 'target'), ...target)

    gl.drawArrays(gl.TRIANGLES, 0, 6)

    const pixels = new Uint8Array(width * height * 4)
    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
    let pos = 'not found'
    for (let i = 0; i < pixels.length; i += 4) {
      if (pixels[i]) {
        pos = (i / 4 + 1000000).toString().substring(1)
        break
      }
    }
    print(pos)
  }
  document.body.appendChild(button)
})()
